/*
 * Lapack.cs
 *
 * LAPACK provider for AMD's ACML.
 *
 * Copyright (c) 2005, dnAnalytics. All rights reserved.
 */
using System;

namespace dnAnalytics.Nli.Acml {
	/// <summary>
	/// Summary description for Mkl Lapack.
	/// </summary>
	internal sealed class Lapack : ILapack {
		private static readonly ILapack instance = new Lapack();

		private Lapack() {}

		#region Public Members

		public static ILapack Instance {
			get { return instance; }
		}

		public int Sgeqp3(int m, int n, float[] a, int lda, int[] jpvt, float[] tau) {
			float[] work = new float[Math.Max(1, 3*n + 1)];
			return Sgeqp3(m, n, a, lda, jpvt, tau, work);
		}

		public int Sgeqp3(int m, int n, float[] a, int lda, int[] jpvt, float[] tau, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sgeqp3_(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, ref info);
			return info;
		}

		public int Sgesvd(char jobu, char jobvt, int m, int n, float[] a, int lda, float[] s, float[] u, int ldu, float[] vt, int ldvt) {
			float[] work = new float[Math.Max((3*Math.Min(m, n) + Math.Max(m, n)), 5*Math.Min(m, n))];
			return Sgesvd(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work);
		}

		public int Sgesvd(char jobu, char jobvt, int m, int n, float[] a, int lda, float[] s, float[] u, int ldu, float[] vt, int ldvt, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sgesvd_(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Sgetrf(int m, int n, float[] a, int lda, out int[] ipiv) {
			int info = 0;
			ipiv = new int[m];
			SafeNativeMethods.sgetrf_(ref m, ref n, a, ref lda, ipiv, ref info);
			return info;
		}

		public int Sgetri(int n, float[] a, int lda, int[] ipiv) {
			int bs = Ilaenv(1, "sgetri_", "", n, -1, -1, -1);
			float[] work = new float[n*bs];
			return Sgetri(n, a, lda, ipiv, work);
		}

		public int Sgetri(int n, float[] a, int lda, int[] ipiv, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sgetri_(ref n, a, ref lda, ipiv, work, ref len, ref info);
			return info;
		}

		public int Sgetrs(char trans, int n, int nrhs, float[] a, int lda, int[] ipiv, float[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.sgetrs_(ref trans, ref n, ref nrhs, a, ref lda, ipiv, b, ref ldb, ref info, 1);
			return info;
		}

		public int Sorgqr(int m, int n, int k, float[] a, int lda, float[] tau) {
			int bs = Ilaenv(1, "sorgqr_", "", m, n, k, -1);
			float[] work = new float[n*bs];
			return Sorgqr(m, n, k, a, lda, tau, work);
		}

		public int Sorgqr(int m, int n, int k, float[] a, int lda, float[] tau, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sorgqr_(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
			return info;
		}

		public int Sormqr(char side, char trans, int m, int n, int k, float[] a, int lda, float[] tau, float[] c, int ldc) {
			string opts = side.ToString() + trans.ToString();
			int bs = Ilaenv(1, "sormqr_", opts, m, n, k, -1);
			float[] work = null;
			if (side == 'L' || side == 'l') {
				work = new float[n*bs];
			} else {
				work = new float[m*bs];
			}
			return Sormqr(side, trans, m, n, k, a, lda, tau, c, ldc, work);
		}

		public int Sormqr(char side, char trans, int m, int n, int k, float[] a, int lda, float[] tau, float[] c, int ldc, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sormqr_(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Spotrf(char uplo, int n, float[] a, int lda) {
			int info = 0;
			SafeNativeMethods.spotrf_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Spotri(char uplo, int n, float[] a, int lda) {
			int info = 0;
			SafeNativeMethods.spotri_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Spotrs(char uplo, int n, int nrhs, float[] a, int lda, float[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.spotrs_(ref uplo, ref n, ref nrhs, a, ref lda, b, ref ldb, ref info, 1);
			return info;
		}

		public int Dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau) {
			double[] work = new double[Math.Max(1, 3*n + 1)];
			return Dgeqp3(m, n, a, lda, jpvt, tau, work);
		}

		public int Dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dgeqp3_(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, ref info);
			return info;
		}

		public int Dgesvd(char jobu, char jobvt, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldvt) {
			double[] work = new double[Math.Max((3*Math.Min(m, n) + Math.Max(m, n)), 5*Math.Min(m, n))];
			return Dgesvd(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work);
		}

		public int Dgesvd(char jobu, char jobvt, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldvt, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dgesvd_(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Dgetrf(int m, int n, double[] a, int lda, out int[] ipiv) {
			int info = 0;
			ipiv = new int[m];
			SafeNativeMethods.dgetrf_(ref m, ref n, a, ref lda, ipiv, ref info);
			return info;
		}

		public int Dgetri(int n, double[] a, int lda, int[] ipiv) {
			int bs = Ilaenv(1, "dgetri_", "", n, -1, -1, -1);
			double[] work = new double[n*bs];
			return Dgetri(n, a, lda, ipiv, work);
		}

		public int Dgetri(int n, double[] a, int lda, int[] ipiv, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dgetri_(ref n, a, ref lda, ipiv, work, ref len, ref info);
			return info;
		}

		public int Dgetrs(char trans, int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.dgetrs_(ref trans, ref n, ref nrhs, a, ref lda, ipiv, b, ref ldb, ref info, 1);
			return info;
		}

		public int Dorgqr(int m, int n, int k, double[] a, int lda, double[] tau) {
			int bs = Ilaenv(1, "dorgqr_", "", m, n, k, -1);
			double[] work = new double[n*bs];
			return Dorgqr(m, n, k, a, lda, tau, work);
		}

		public int Dorgqr(int m, int n, int k, double[] a, int lda, double[] tau, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dorgqr_(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
			return info;
		}

		public int Dormqr(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc) {
			string opts = side.ToString() + trans.ToString();
			int bs = Ilaenv(1, "dormqr_", opts, m, n, k, -1);
			double[] work = null;
			if (side == 'L' || side == 'l') {
				work = new double[n*bs];
			} else {
				work = new double[m*bs];
			}
			return Dormqr(side, trans, m, n, k, a, lda, tau, c, ldc, work);
		}

		public int Dormqr(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dormqr_(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Dpotrf(char uplo, int n, double[] a, int lda) {
			int info = 0;
			SafeNativeMethods.dpotrf_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Dpotri(char uplo, int n, double[] a, int lda) {
			int info = 0;
			SafeNativeMethods.dpotri_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Dpotrs(char uplo, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.dpotrs_(ref uplo, ref n, ref nrhs, a, ref lda, b, ref ldb, ref info, 1);
			return info;
		}

		public int Cgeqp3(int m, int n, ComplexFloat[] a, int lda, int[] jpvt, ComplexFloat[] tau) {
			ComplexFloat[] work = new ComplexFloat[Math.Max(1, n + 1)];
			float[] rwork = new float[Math.Max(1, 2*n)];
			return Cgeqp3(m, n, a, lda, jpvt, tau, work, rwork);
		}

		public int Cgeqp3(int m, int n, ComplexFloat[] a, int lda, int[] jpvt, ComplexFloat[] tau, ComplexFloat[] work, float[] rwork) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cgeqp3_(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, rwork, ref info);
			return info;
		}

		public int Cgetrf(int m, int n, ComplexFloat[] a, int lda, out int[] ipiv) {
			int info = 0;
			ipiv = new int[m];
			SafeNativeMethods.cgetrf_(ref m, ref n, a, ref lda, ipiv, ref info);
			return info;
		}

		public int Cgetri(int n, ComplexFloat[] a, int lda, int[] ipiv) {
			int bs = Ilaenv(1, "cgetri_", "", n, -1, -1, -1);
			ComplexFloat[] work = new ComplexFloat[n*bs];
			return Cgetri(n, a, lda, ipiv, work);
		}

		public int Cgetri(int n, ComplexFloat[] a, int lda, int[] ipiv, ComplexFloat[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cgetri_(ref n, a, ref lda, ipiv, work, ref len, ref info);
			return info;
		}

		public int Cgetrs(char trans, int n, int nrhs, ComplexFloat[] a, int lda, int[] ipiv, ComplexFloat[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.cgetrs_(ref trans, ref n, ref nrhs, a, ref lda, ipiv, b, ref ldb, ref info, 1);
			return info;
		}

		public int Cpotrf(char uplo, int n, ComplexFloat[] a, int lda) {
			int info = 0;
			SafeNativeMethods.cpotrf_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Cpotri(char uplo, int n, ComplexFloat[] a, int lda) {
			int info = 0;
			SafeNativeMethods.cpotri_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Cpotrs(char uplo, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.cpotrs_(ref uplo, ref n, ref nrhs, a, ref lda, b, ref ldb, ref info, 1);
			return info;
		}

		public int Cungqr(int m, int n, int k, ComplexFloat[] a, int lda, ComplexFloat[] tau) {
			int bs = Ilaenv(1, "cungqr_", "", m, n, k, -1);
			ComplexFloat[] work = new ComplexFloat[n*bs];
			return Cungqr(m, n, k, a, lda, tau, work);
		}

		public int Cungqr(int m, int n, int k, ComplexFloat[] a, int lda, ComplexFloat[] tau, ComplexFloat[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cungqr_(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
			return info;
		}

		public int Cunmqr(char side, char trans, int m, int n, int k, ComplexFloat[] a, int lda, ComplexFloat[] tau, ComplexFloat[] c, int ldc) {
			string opts = side.ToString() + trans.ToString();
			int bs = Ilaenv(1, "cunmqr_", opts, m, n, k, -1);
			ComplexFloat[] work = null;
			if (side == 'L' || side == 'l') {
				work = new ComplexFloat[n*bs];
			} else {
				work = new ComplexFloat[m*bs];
			}
			return Cunmqr(side, trans, m, n, k, a, lda, tau, c, ldc, work);
		}

		public int Cunmqr(char side, char trans, int m, int n, int k, ComplexFloat[] a, int lda, ComplexFloat[] tau, ComplexFloat[] c, int ldc, ComplexFloat[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cunmqr_(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Zgeqp3(int m, int n, ComplexDouble[] a, int lda, int[] jpvt, ComplexDouble[] tau) {
			ComplexDouble[] work = new ComplexDouble[Math.Max(1, n + 1)];
			double[] rwork = new double[Math.Max(1, 2*n)];
			return Zgeqp3(m, n, a, lda, jpvt, tau, work, rwork);
		}

		public int Zgeqp3(int m, int n, ComplexDouble[] a, int lda, int[] jpvt, ComplexDouble[] tau, ComplexDouble[] work, double[] rwork) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.zgeqp3_(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, rwork, ref info);
			return info;
		}

		public int Zgetrf(int m, int n, ComplexDouble[] a, int lda, out int[] ipiv) {
			int info = 0;
			ipiv = new int[m];
			SafeNativeMethods.zgetrf_(ref m, ref n, a, ref lda, ipiv, ref info);
			return info;
		}

		public int Zgetri(int n, ComplexDouble[] a, int lda, int[] ipiv) {
			int bs = Ilaenv(1, "zgetri_", "", n, -1, -1, -1);
			ComplexDouble[] work = new ComplexDouble[n*bs];
			return Zgetri(n, a, lda, ipiv, work);
		}

		public int Zgetri(int n, ComplexDouble[] a, int lda, int[] ipiv, ComplexDouble[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.zgetri_(ref n, a, ref lda, ipiv, work, ref len, ref info);
			return info;
		}

		public int Zgetrs(char trans, int n, int nrhs, ComplexDouble[] a, int lda, int[] ipiv, ComplexDouble[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.zgetrs_(ref trans, ref n, ref nrhs, a, ref lda, ipiv, b, ref ldb, ref info, 1);
			return info;
		}

		public int Zpotrf(char uplo, int n, ComplexDouble[] a, int lda) {
			int info = 0;
			SafeNativeMethods.zpotrf_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Zpotri(char uplo, int n, ComplexDouble[] a, int lda) {
			int info = 0;
			SafeNativeMethods.zpotri_(ref uplo, ref n, a, ref lda, ref info, 1);
			return info;
		}

		public int Zpotrs(char uplo, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb) {
			int info = 0;
			SafeNativeMethods.zpotrs_(ref uplo, ref n, ref nrhs, a, ref lda, b, ref ldb, ref info, 1);
			return info;
		}

		public int Zungqr(int m, int n, int k, ComplexDouble[] a, int lda, ComplexDouble[] tau) {
			int bs = Ilaenv(1, "zungqr_", "", m, n, k, -1);
			ComplexDouble[] work = new ComplexDouble[n*bs];
			return Zungqr(m, n, k, a, lda, tau, work);
		}

		public int Zungqr(int m, int n, int k, ComplexDouble[] a, int lda, ComplexDouble[] tau, ComplexDouble[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.zungqr_(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
			return info;
		}

		public int Zunmqr(char side, char trans, int m, int n, int k, ComplexDouble[] a, int lda, ComplexDouble[] tau, ComplexDouble[] c, int ldc) {
			string opts = side.ToString() + trans.ToString();
			int bs = Ilaenv(1, "zunmqr_", opts, m, n, k, -1);
			ComplexDouble[] work = null;
			if (side == 'L' || side == 'l') {
				work = new ComplexDouble[n*bs];
			} else {
				work = new ComplexDouble[m*bs];
			}
			return Zunmqr(side, trans, m, n, k, a, lda, tau, c, ldc, work);
		}

		public int Zunmqr(char side, char trans, int m, int n, int k, ComplexDouble[] a, int lda, ComplexDouble[] tau, ComplexDouble[] c, int ldc, ComplexDouble[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.zunmqr_(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Cgesvd(char jobu, char jobvt, int m, int n, ComplexFloat[] a, int lda, float[] s, ComplexFloat[] u, int ldu, ComplexFloat[] vt, int ldvt) {
			ComplexFloat[] work = new ComplexFloat[2*Math.Min(m, n) + Math.Max(m, n)];
			float[] rwork = new float[Math.Max(1, 5*Math.Min(m, n))];
			return Cgesvd(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work, rwork);
		}

		public int Zgesvd(char jobu, char jobvt, int m, int n, ComplexDouble[] a, int lda, double[] s, ComplexDouble[] u, int ldu, ComplexDouble[] vt, int ldvt) {
			ComplexDouble[] work = new ComplexDouble[2*Math.Min(m, n) + Math.Max(m, n)];
			double[] rwork = new double[Math.Max(1, 5*Math.Min(m, n))];
			return Zgesvd(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work, rwork);
		}

		public int Cgesvd(char jobu, char jobvt, int m, int n, ComplexFloat[] a, int lda, float[] s, ComplexFloat[] u, int ldu, ComplexFloat[] vt, int ldvt, ComplexFloat[] work, float[] rwork) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cgesvd_(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, rwork, ref info, 1, 1);
			return info;
		}

		public int Zgesvd(char jobu, char jobvt, int m, int n, ComplexDouble[] a, int lda, double[] s, ComplexDouble[] u, int ldu, ComplexDouble[] vt, int ldvt, ComplexDouble[] work, double[] rwork) {
			int info = 0;
			int len = work.Length;

			SafeNativeMethods.zgesvd_(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, rwork, ref info, 1, 1);
			return info;
		}

		public int Sgels(char trans, int m, int n, int nrhs, float[] a, int lda, float[] b, int ldb) {
			int bs = Ilaenv(1, "sgels_", trans.ToString(), m, n, nrhs, -1);
			float[] work = new float[Math.Min(m, n) + Math.Max(m, Math.Max(n, nrhs))*bs];
			return Sgels(trans, m, n, nrhs, a, lda, b, ldb, work);
		}

		public int Sgels(char trans, int m, int n, int nrhs, float[] a, int lda, float[] b, int ldb, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sgels_(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
			return info;
		}

		public int Cgels(char trans, int m, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb) {
			int bs = Ilaenv(1, "cgels_", trans.ToString(), m, n, nrhs, -1);
			ComplexFloat[] work = new ComplexFloat[Math.Min(m, n) + Math.Max(m, Math.Max(n, nrhs))*bs];
			return Cgels(trans, m, n, nrhs, a, lda, b, ldb, work);
		}

		public int Cgels(char trans, int m, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb, ComplexFloat[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cgels_(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
			return info;
		}

		public int Dgels(char trans, int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
			int bs = Ilaenv(1, "dgels_", trans.ToString(), m, n, nrhs, -1);
			double[] work = new double[Math.Min(m, n) + Math.Max(m, Math.Max(n, nrhs))*bs];
			return Dgels(trans, m, n, nrhs, a, lda, b, ldb, work);
		}

		public int Dgels(char trans, int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dgels_(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
			return info;
		}

		public int Zgels(char trans, int m, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb) {
			int bs = Ilaenv(1, "zgels_", trans.ToString(), m, n, nrhs, -1);
			ComplexDouble[] work = new ComplexDouble[Math.Min(m, n) + Math.Max(m, Math.Max(n, nrhs))*bs];
			return Zgels(trans, m, n, nrhs, a, lda, b, ldb, work);
		}

		public int Zgels(char trans, int m, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb, ComplexDouble[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.zgels_(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
			return info;
		}

		public int Sgelss(int m, int n, int nrhs, float[] a, int lda, float[] b, int ldb, out float[] s, ref int rank) {
			float[] work = new float[3*Math.Min(m, n) + Math.Max(2*Math.Min(m, n), Math.Max(Math.Max(m, n), nrhs))];
			float rcond = -1;
			return Sgelss(m, n, nrhs, a, lda, b, ldb, out s, rcond, ref rank, work);
		}

		public int Sgelss(int m, int n, int nrhs, float[] a, int lda, float[] b, int ldb, out float[] s, float rcond, ref int rank, float[] work) {
			int info = 0;
			int len = work.Length;
			s = new float[Math.Min(m, n)];
			SafeNativeMethods.sgelss_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, ref info);
			return info;
		}

		public int Dgelss(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, out double[] s, ref int rank) {
			double[] work = new double[3*Math.Min(m, n) + Math.Max(2*Math.Min(m, n), Math.Max(Math.Max(m, n), nrhs))];
			double rcond = -1;
			return Dgelss(m, n, nrhs, a, lda, b, ldb, out s, rcond, ref rank, work);
		}

		public int Dgelss(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, out double[] s, double rcond, ref int rank, double[] work) {
			int info = 0;
			int len = work.Length;
			s = new double[Math.Min(m, n)];
			SafeNativeMethods.dgelss_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, ref info);
			return info;
		}

		public int Cgelss(int m, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb, out float[] s, ref int rank) {
			ComplexFloat[] work = new ComplexFloat[3*Math.Min(m, n) + Math.Max(2*Math.Min(m, n), Math.Max(Math.Max(m, n), nrhs))];
			float[] rwork = new float[Math.Max(1, 5*Math.Min(m, n))];
			float rcond = -1;
			return Cgelss(m, n, nrhs, a, lda, b, ldb, out s, rcond, ref rank, work, rwork);
		}

		public int Cgelss(int m, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb, out float[] s, float rcond, ref int rank, ComplexFloat[] work, float[] rwork) {
			int info = 0;
			int len = work.Length;
			s = new float[Math.Min(m, n)];
			SafeNativeMethods.cgelss_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, rwork, ref info);
			return info;
		}

		public int Zgelss(int m, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb, out double[] s, ref int rank) {
			ComplexDouble[] work = new ComplexDouble[3*Math.Min(m, n) + Math.Max(2*Math.Min(m, n), Math.Max(Math.Max(m, n), nrhs))];
			double[] rwork = new double[Math.Max(1, 5*Math.Min(m, n))];
			double rcond = -1;
			return Zgelss(m, n, nrhs, a, lda, b, ldb, out s, rcond, ref rank, work, rwork);
		}

		public int Zgelss(int m, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb, out double[] s, double rcond, ref int rank, ComplexDouble[] work, double[] rwork) {
			int info = 0;
			int len = work.Length;
			s = new double[Math.Min(m, n)];
			SafeNativeMethods.zgelss_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, rwork, ref info);
			return info;
		}

		public int Sgelsy(int m, int n, int nrhs, float[] a, int lda, float[] b, int ldb, int[] jpvt, float rcond, ref int rank) {
			int nb = Ilaenv(1, "sgelsy_", "", m, n, nrhs, -1);
			int mn = Math.Min(m, n);
			int len = Math.Max((mn + 2)*n + nb*(n + 1), 2*mn + nb*nrhs);
			float[] work = new float[len];
			return Sgelsy(m, n, nrhs, a, lda, b, ldb, jpvt, rcond, ref rank, work);
		}

		public int Sgelsy(int m, int n, int nrhs, float[] a, int lda, float[] b, int ldb, int[] jpvt, float rcond, ref int rank, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sgelsy_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, ref info);
			return info;
		}

		public int Dgelsy(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, int[] jpvt, double rcond, ref int rank) {
			int nb = Ilaenv(1, "dgelsy_", "", m, n, nrhs, -1);
			int mn = Math.Min(m, n);
			int len = Math.Max((mn + 2)*n + nb*(n + 1), 2*mn + nb*nrhs);
			double[] work = new double[len];
			return Dgelsy(m, n, nrhs, a, lda, b, ldb, jpvt, rcond, ref rank, work);
		}

		public int Dgelsy(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, int[] jpvt, double rcond, ref int rank, double[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.dgelsy_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, ref info);
			return info;
		}

		public int Cgelsy(int m, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb, int[] jpvt, float rcond, ref int rank) {
			int nb = Ilaenv(1, "cgelsy_", "", m, n, nrhs, -1);
			int mn = Math.Min(m, n);
			int len = mn + Math.Max(Math.Max(Math.Max(2*mn, nb*(n + 1)), mn + mn*nb), mn + nb*nrhs);
			ComplexFloat[] work = new ComplexFloat[len];
			float[] rwork = new float[Math.Max(1, 2*n)];
			return Cgelsy(m, n, nrhs, a, lda, b, ldb, jpvt, rcond, ref rank, work, rwork);
		}

		public int Cgelsy(int m, int n, int nrhs, ComplexFloat[] a, int lda, ComplexFloat[] b, int ldb, int[] jpvt, float rcond, ref int rank, ComplexFloat[] work, float[] rwork) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.cgelsy_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, rwork, ref info);
			return info;
		}

		public int Zgelsy(int m, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb, int[] jpvt, double rcond, ref int rank) {
			int nb = Ilaenv(1, "zgelsy_", "", m, n, nrhs, -1);
			int mn = Math.Min(m, n);
			int len = mn + Math.Max(Math.Max(Math.Max(2*mn, nb*(n + 1)), mn + mn*nb), mn + nb*nrhs);
			ComplexDouble[] work = new ComplexDouble[len];
			double[] rwork = new double[Math.Max(1, 2*n)];
			return Zgelsy(m, n, nrhs, a, lda, b, ldb, jpvt, rcond, ref rank, work, rwork);
		}

		public int Zgelsy(int m, int n, int nrhs, ComplexDouble[] a, int lda, ComplexDouble[] b, int ldb, int[] jpvt, double rcond, ref int rank, ComplexDouble[] work, double[] rwork) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.zgelsy_(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, rwork, ref info);
			return info;
		}

		public float Slange(char norm, int m, int n, float[] a, int lda) {
			float[] work = new float[m];
			return Slange(norm, m, n, a, lda, work);
		}

		public float Slange(char norm, int m, int n, float[] a, int lda, float[] work) {
			return SafeNativeMethods.slange_(ref norm, ref m, ref n, a, ref lda, work, 1);
		}

		public double Dlange(char norm, int m, int n, double[] a, int lda) {
			double[] work = new double[m];
			return Dlange(norm, m, n, a, lda, work);
		}

		public double Dlange(char norm, int m, int n, double[] a, int lda, double[] work) {
			return SafeNativeMethods.dlange_(ref norm, ref m, ref n, a, ref lda, work, 1);
		}

		public float Clange(char norm, int m, int n, ComplexFloat[] a, int lda) {
			float[] work = new float[m];
			return Clange(norm, m, n, a, lda, work);
		}

		public float Clange(char norm, int m, int n, ComplexFloat[] a, int lda, float[] work) {
			return SafeNativeMethods.clange_(ref norm, ref m, ref n, a, ref lda, work, 1);
		}

		public double Zlange(char norm, int m, int n, ComplexDouble[] a, int lda) {
			double[] work = new double[m];
			return Zlange(norm, m, n, a, lda, work);
		}

		public double Zlange(char norm, int m, int n, ComplexDouble[] a, int lda, double[] work) {
			return SafeNativeMethods.zlange_(ref norm, ref m, ref n, a, ref lda, work, 1);
		}

		public int Sgecon(char norm, int n, float[] a, int lda, float anorm, ref float rcond) {
			float[] work = new float[Math.Max(1, 4*n)];
			int[] iwork = new int[Math.Max(1, n)];
			return Sgecon(norm, n, a, lda, anorm, ref rcond, work, iwork);
		}

		public int Sgecon(char norm, int n, float[] a, int lda, float anorm, ref float rcond, float[] work, int[] iwork) {
			int info = 0;
			SafeNativeMethods.sgecon_(ref norm, ref n, a, ref lda, ref anorm, ref rcond, work, iwork, ref info, 1);
			return info;
		}

		public int Dgecon(char norm, int n, double[] a, int lda, double anorm, ref double rcond) {
			double[] work = new double[Math.Max(1, 4*n)];
			int[] iwork = new int[Math.Max(1, n)];
			return Dgecon(norm, n, a, lda, anorm, ref rcond, work, iwork);
		}

		public int Dgecon(char norm, int n, double[] a, int lda, double anorm, ref double rcond, double[] work, int[] iwork) {
			int info = 0;
			SafeNativeMethods.dgecon_(ref norm, ref n, a, ref lda, ref anorm, ref rcond, work, iwork, ref info, 1);
			return info;
		}

		public int Cgecon(char norm, int n, ComplexFloat[] a, int lda, float anorm, ref float rcond) {
			ComplexFloat[] work = new ComplexFloat[Math.Max(1, 4*n)];
			float[] rwork = new float[Math.Max(1, 2*n)];
			return Cgecon(norm, n, a, lda, anorm, ref rcond, work, rwork);
		}

		public int Cgecon(char norm, int n, ComplexFloat[] a, int lda, float anorm, ref float rcond, ComplexFloat[] work, float[] rwork) {
			int info = 0;
			SafeNativeMethods.cgecon_(ref norm, ref n, a, ref lda, ref anorm, ref rcond, work, rwork, ref info, 1);
			return info;
		}

		public int Zgecon(char norm, int n, ComplexDouble[] a, int lda, double anorm, ref double rcond) {
			ComplexDouble[] work = new ComplexDouble[Math.Max(1, 4*n)];
			double[] rwork = new double[Math.Max(1, 2*n)];
			return Zgecon(norm, n, a, lda, anorm, ref rcond, work, rwork);
		}

		public int Zgecon(char norm, int n, ComplexDouble[] a, int lda, double anorm, ref double rcond, ComplexDouble[] work, double[] rwork) {
			int info = 0;
			SafeNativeMethods.zgecon_(ref norm, ref n, a, ref lda, ref anorm, ref rcond, work, rwork, ref info, 1);
			return info;
		}

		public int Sggev(char jobvl, char jobvr, int n, float[] a, int lda, float[] b, int ldb, float[] alphar, float[] alphai, float[] beta, float[] vl, int ldvl, float[] vr, int ldvr) {
			float[] work = new float[Math.Max(1, 8*n+16)];		
			return Sggev(jobvl, jobvr, n, a, lda, b, ldb, alphar, alphai, beta, vl, ldvl, vr, ldvr, work );
		}

		public int Sggev(char jobvl, char jobvr, int n, float[] a, int lda, float[] b, int ldb, float[] alphar, float[] alphai, float[] beta, float[] vl, int ldvl, float[] vr, int ldvr, float[] work) {
			int info = 0;
			int len = work.Length;
			SafeNativeMethods.sggev_(ref jobvl, ref jobvr, ref n, a, ref lda, b, ref ldb, alphar, alphai, beta, vl, ref ldvl, vr, ref ldvr, work, ref len, ref info, 1, 1);
			return info;
		}

		public int Ilaenv(int ispec, string name, string opts, int n1, int n2, int n3, int n4) {
			return SafeNativeMethods.ilaenv_(ref ispec, name, opts, ref n1, ref n2, ref n3, ref n4, name.Length, opts.Length);
		}

		#endregion Public Members
	}
}